﻿
using System;
using System.IO;

namespace CNative.Utilities
{
#if !net40
    using Microsoft.Extensions.Logging;

    public static class NlogHelper
    {
        /// <summary>
        /// Represents a type used to perform logging.
        /// </summary>
        public static ILogger Logger { get; set; } //= new Log4Net.Log4NetLogger();

        public static bool IsTraceEnabled { get { return Logger?.IsEnabled(LogLevel.Trace) == true; } }
        public static bool IsWarnEnabled { get { return Logger?.IsEnabled(LogLevel.Warning) == true; } }
        public static bool IsInfoEnabled { get { return Logger?.IsEnabled(LogLevel.Information) == true; } }
        public static bool IsDebugEnabled { get { return Logger?.IsEnabled(LogLevel.Debug) == true; } }
        public static bool IsErrorEnabled { get { return Logger?.IsEnabled(LogLevel.Error) == true; } }
        public static bool IsCriticalEnabled { get { return Logger?.IsEnabled(LogLevel.Critical) == true; } }

#else
    public static class NlogHelper
    {
        /// <summary>
        /// Represents a type used to perform logging.
        /// </summary>
        public static NLog.Logger Logger { get; set; } //= NLog.LogManager.GetCurrentClassLogger();

        public static bool IsTraceEnabled { get { return Logger?.IsEnabled(NLog.LogLevel.Trace) == true; } }
        public static bool IsWarnEnabled { get { return Logger?.IsEnabled(NLog.LogLevel.Warn) == true; } }
        public static bool IsInfoEnabled { get { return Logger?.IsEnabled(NLog.LogLevel.Info) == true; } }
        public static bool IsDebugEnabled { get { return Logger?.IsEnabled(NLog.LogLevel.Debug) == true; } }
        public static bool IsErrorEnabled { get { return Logger?.IsEnabled(NLog.LogLevel.Error) == true; } }
        public static bool IsCriticalEnabled { get { return Logger?.IsEnabled(NLog.LogLevel.Fatal) == true; } }

#endif


        public static bool UseDispatcher { get; set; } = true;
        private static Dispatchs.SingleThreadDispatcher<Action> mDispatcher;

        static NlogHelper()
        {
            try
            {
#if !net40
                Logger = new CNative.Utilities.Nlog.FileLogger("Nlog");
#else
                Logger = NLog.LogManager.GetCurrentClassLogger();
#endif
                mDispatcher = new Dispatchs.SingleThreadDispatcher<Action>(OnWriteLog);
                UseDispatcher = true;

            }
            catch (Exception e)
            {
                throw new Exception("加载日志配置文件失败", e);
            }
        }

        public static void AddAction(Action e)
        {
            if (UseDispatcher)
                mDispatcher.Enqueue(e);
        }

        private static void OnWriteLog(Action process)
        {
            try
            {
                process.Invoke();
            }
            catch (Exception e_)
            {
                try
                {
#if !net40
                    Logger?.LogWarning("OnWriteLog Exception:{0}", e_?.ToString());
#else
                    Logger?.Warn("OnWriteLog Exception:{0}", e_?.ToString());
#endif
                }
                catch { }
            }
        }


        /// <summary>
        /// Trace
        /// </summary>
        /// <param name="message"></param>
        public static void Trace(this object message)
        {
            if (IsTraceEnabled)
            {
#if !net40
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.LogTrace(message?.ToString()));
                }
                else
                    Logger?.LogTrace(message?.ToString());
#else
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.Trace(message?.ToString()));
                }
                else
                    Logger?.Trace(message?.ToString());
#endif
            }
        }

        /// <summary>
        /// Debug
        /// </summary>
        /// <param name="message"></param>
        public static void Debug(object message)
        {
            if (IsDebugEnabled)
            {
#if !net40
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.LogDebug(message?.ToString()));
                }
                else
                    Logger?.LogDebug(message?.ToString());
#else
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.Debug(message?.ToString()));
                }
                else
                    Logger?.Debug(message?.ToString());
#endif
            }

        }

        /// <summary>
        /// Info
        /// </summary>
        /// <param name="message"></param>
        public static void Info(this object message)
        {
            if (IsInfoEnabled)
            {
#if !net40
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.LogInformation(message?.ToString()));
                }
                else
                    Logger?.LogInformation(message?.ToString());
#else
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.Info(message?.ToString()));
                }
                else
                    Logger?.Info(message?.ToString());
#endif
            }
        }

        /// <summary>
        /// Warn
        /// </summary>
        /// <param name="message"></param>
        public static void Warn(this object message)
        {
            if (IsWarnEnabled)
            {
#if !net40
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.LogWarning(message?.ToString()));
                }
                else
                    Logger?.LogWarning(message?.ToString());
#else
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.Warn(message?.ToString()));
                }
                else
                    Logger?.Warn(message?.ToString());
#endif
            }
        }
        public static void Warn(this Exception exception, object message)
        { Warn(message, exception); }
        public static void Warn(this object message, Exception exception)
        { Warn(message?.ToString() + " StackTrace:" + exception.GetExceptionMessage()); }

        /// <summary>
        /// Error
        /// </summary>
        /// <param name="message"></param>
        public static void Error(this object message)
        {
            if (IsErrorEnabled)
            {
#if !net40
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.LogError(message?.ToString()));
                }
                else
                    Logger?.LogError(message?.ToString());
#else
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.Error(message?.ToString()));
                }
                else
                    Logger?.Error(message?.ToString());
#endif
            }
        }
        public static void Error(this Exception exception, object message)
        { Error(message, exception); }
        public static void Error(this object message, Exception exception)
        { Error(message?.ToString() + " StackTrace:" + exception.GetExceptionMessage()); }

        /// <summary>
        /// /Critical
        /// </summary>
        /// <param name="message"></param>
        public static void Critical(this object message)
        {
            if (IsCriticalEnabled)
            {
#if !net40
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.LogCritical(message?.ToString()));
                }
                else
                    Logger?.LogCritical(message?.ToString());
#else
                if (UseDispatcher)
                {
                    AddAction(() => Logger?.Fatal(message?.ToString()));
                }
                else
                    Logger?.Fatal(message?.ToString());
#endif
            }
        }
        public static void Critical(this Exception exception, object message)
        { Critical(message, exception); }
        public static void Critical(this object message, Exception exception)
        { Critical(message?.ToString() + " StackTrace:" + exception.GetExceptionMessage()); }

        /// <summary>
        /// /Critical
        /// </summary>
        /// <param name="message"></param>
        public static void Fatal(this object message)
        { Critical(message); }
        public static void Fatal(this Exception exception, object message)
        { Critical(message, exception); }
        public static void Fatal(this object message, Exception exception)
        { Critical(message, exception); }

#if !net40
        /// <summary>
        /// 实现接口ILogger
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <param name="logLevel"></param>
        /// <param name="eventId"></param>
        /// <param name="state"></param>
        /// <param name="exception"></param>
        /// <param name="formatter"></param>
        public static void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (!Logger.IsEnabled(logLevel))
            {
                return;
            }
            if (UseDispatcher)
            {
                AddAction(() => Logger?.Log(logLevel, eventId, state, exception, formatter));
            }
            else
                Logger?.Log(logLevel, eventId, state, exception, formatter);
        }
#else
        /// <summary>
        /// 实现接口ILogger
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <param name="logLevel"></param>
        /// <param name="eventId"></param>
        /// <param name="state"></param>
        /// <param name="exception"></param>
        /// <param name="formatter"></param>
        public static void Log<TState>(NLog.LogLevel logLevel, string message, Exception exception)
        {
            if (!Logger.IsEnabled(logLevel))
            {
                return;
            }
            if (UseDispatcher)
            {
                AddAction(() => Logger?.Log(logLevel, message, exception));
            }
            else
                Logger?.Log(logLevel, message, exception);
        }
#endif
    }
}
